



class BoardPath implements Comparable<BoardPath>
	{
	
		public static enum BeginDirection
		{
			Forward,
			Backwards;
		}
	
		public Board board;
		public String path;
		public int depth;
		
		public BeginDirection beginDirection;
		public VisitedEntry lastVisitedEntry;
		
		public int calculatedHeuristic;
		
//		public int[][] boxManhattanDistanceMatrix;
		public DistanceCache distanceCache;
		
//		private static int DEPTH_PER_ITERATION = 3;
		
//		public BoardPath( BoardImplFast board, String path, int depth, BeginDirection beginDirection, 
//				int[][] boxManhattanDistanceMatrix, VisitedEntry lastVisitedEntry, DistanceCache distanceCache )
		public BoardPath( Board board, String path, int depth, BeginDirection beginDirection, 
				VisitedEntry lastVisitedEntry, DistanceCache distanceCache )
		{
			this.board = board;
			this.path = path;
			
			this.depth = depth;
			
			this.beginDirection = beginDirection;
			
//			this.boxManhattanDistanceMatrix = boxManhattanDistanceMatrix;
			
			this.lastVisitedEntry = lastVisitedEntry;
			
			this.distanceCache = distanceCache;
			
			calculatedHeuristic = aStarHeuristic();
			
		}
		
//		public static int manhattanDistance( Cord c1, Cord c2 )
//		{
//			return (Math.abs( c1.getX()-c2.getX() ) + Math.abs( c1.getY()-c2.getY() ));
//		}
//		
//		public static int minimumManhattanDistance( Board board, Cord start, Cord[] goals )
//		{
//			int min = Integer.MAX_VALUE;
//			
//			boolean found = false;
//			for( Cord goal : goals )
//			{ 
//				if (!found)
//				{
//					min = manhattanDistance(start, goal);
//					found = true;
//				}
//				else
//				{
//					min = Math.min( min , manhattanDistance(start, goal) );
//				}
//
//			}
//			
//			return min;
//		}
		
//		private int minimumManhattanDistanceNotGoal( Board board, Cord start, Cord[] goals )
//		{
//			int min = Integer.MAX_VALUE;
//			
//			for( Cord goal : goals )
//			{ 
////				if ( board.getCellType( start ) != Board.CellType.BoxOnGoal )
////				if ( board.getCellType( goal ) != Board.CellType.BoxOnGoal )
////				{
//					min = Math.min( min , manhattanDistance(start, goal) );
////				}
//				
//			}
//			
//			return min;
//		}
		
//		private int getDepth()
//		{
//			return depth;
//		}

		@Override
		public int compareTo(BoardPath arg0) 
		{
//			int refDepth = arg0.getDepthLevel();
//			int selfDepth = this.getDepthLevel();
			
			
//			if ( selfDepth > refDepth )
//			{
////				System.out.println("selfDepth:refDepth = "+ selfDepth +">"+refDepth );
//				return 1;
//			}
//			else if ( selfDepth < refDepth )
//			{
////				System.out.println("selfDepth:refDepth = "+ selfDepth +"<"+refDepth );
//				return -1;
//			}
//			else
//			{
				
				int ref = arg0.calculatedHeuristic;
				int self = this.calculatedHeuristic;
				
				if ( self < ref )
				{
					return -1;
				}
				else if ( self > ref )
				{
					return 1;
				}
				else
				{
					return 0;
//					return Integer.parseInt(path);
//					return aStarHeuristic();
				}
				
//			}
		}
		
	
		public int aStarHeuristic()
		{	
			if ( board.isFinished() )
			{
				return Integer.MIN_VALUE;
			}
			
			Cord[] goals = board.getGoals();
			Cord[] boxes = board.getBoxes();
			Cord player = board.getPlayer();
			

			int score = 0;

////			score += minimumManhattanDistanceNotGoal(board, player, boxes)^2;
//			score += minimumManhattanDistance(board, player, boxes)^2;
////			score += minimumManhattanDistance(board, player, boxes)*boxes.length;
//
//			for ( Cord box : boxes )
//			{
////				score += minimumManhattanDistanceNotGoal(board, box, goals);
////				score += minimumManhattanDistance(board, box, goals);
//				
//				score += boxManhattanDistanceMatrix[ box.getX() ][ box.getY() ];
//				
//			}
			

//			score += distanceCache.minimumPlayerDistance(board, player, boxes)^2;
			score += distanceCache.minimumPlayerDistance(board, player, boxes);
			
			for ( Cord box : boxes )
			{

				score += distanceCache.minimumBoxDistance( board, box, goals );
				
			}
			
//			/*
//			 * Goal-macro
//			 */
//			for ( Cord goal : goals )
//			{
//				if ( board.getCellType(goal).isBox() )
//				{
//					int numberOfMovesToThis = 0;
//					for ( Move.Direction direction : Move.Direction.values() )
//					{
//						if ( board.getCellType( goal.getX()+direction.getXDiff(), goal.getY()+direction.getYDiff()  ).notWallOrBox() )
//						{
//							numberOfMovesToThis++;
//						}
//					}
//					
//					score += GOAL_MACRO_VALUES[numberOfMovesToThis];
//					
//				}
//			}
			
			
//			score += minimumPathFromPlayer;
			
//			System.out.println(score);
			
			return score;
			
//			return 0;
		}
		
//		public final int[] GOAL_MACRO_VALUES = {-0,0,0,0,0};
//		public final int[] GOAL_MACRO_VALUES = {-100,-4,-2,-1,0};
//		public final int[] GOAL_MACRO_VALUES = {-100,0,0,0,0};
	}